<?php
/**
 * Created by PhpStorm.
 * User: Jan-Home
 * Date: 2018/10/20 0020
 * Time: 10:10
 */

use PHPUnit\Framework\TestCase;

use Ke\Utils\PathHelper;

class Test_PathHelper extends TestCase
{
	
	use \Ke\TestUtils\TestClassInstanceTrait;
	
	/** @var PathHelper */
	private $helper = null;
	
	protected function setUp()
	{
		$this->helper = new PathHelper();
		$this->setTestInstance($this->helper);
	}
	
	/**
	 * @testMethod absolute
	 */
	public function test_absolute()
	{
		$this->runMethodTest(
			$this->getLastAnnotationTestMethod(),
			[
				[realpath('any/a.php'), 'any/a.php'],
				[realpath('any/b.php'), 'any/b.php'],
				['phar://./any/test.phar/hello/a.php', 'phar://./any/test.phar/hello/a.php'],
			],
			function (PathHelper $helper, $index, \Ke\TestUtils\TestItem $item) {
				$item->setExcepted($helper->convertDirectorySeparator($item->excepted));
			},
			function (PathHelper $helper, $index, \Ke\TestUtils\TestItem $item) {
				$this->assertSame($item->excepted, $item->invoke());
			}
		)->throwLastException();
	}
	
	/**
	 * @testMethod purge
	 */
	public function test_purge_dot_remove()
	{
		$this->runMethodTest(
			$this->getLastAnnotationTestMethod(),
			[
				[
					'a/b',
					['/a/./../b/./../.././', PathHelper::DOT_REMOVE],
				],
				[
					'a/d/e/f',
					['/a/b/c/../../d/e/f', PathHelper::DOT_NORMALIZE],
				],
				[
					'a/./../b/./../.././C',
					['/a/./../b/./../.././C', PathHelper::DOT_ORIGINAL],
				],
				[
					'/',
					['/', PathHelper::LR_FILL],
				],
				[
					'/',
					['', PathHelper::LR_FILL],
				],
				[
					'',
					['', PathHelper::LR_ORIGINAL],
				],
				[
					'/',
					['/', PathHelper::LR_ORIGINAL],
				],
				[
					'/a/b/',
					['/a/b/', PathHelper::LR_ORIGINAL],
				],
				[
					'/c/d',
					['/c\\./d/', PathHelper::LEFT_ORIGINAL | PathHelper::RIGHT_REMOVE],
				],
				[
					'd:/temp/logs/http.log',
					['d:\\temp\\http-2.2.4\\..\\logs\\http.log', PathHelper::DOT_NORMALIZE | PathHelper::RIGHT_ORIGINAL],
				],
				[
					'd:/temp/logs/aaa/',
					['d:\\temp\\http-2.2.4\\..\\logs\\aaa', PathHelper::DOT_NORMALIZE | PathHelper::RIGHT_FILL],
				],
				[
					'a-b-c-d', // 测试非目录分隔符的处理
					['a-tt-..-.-b---c---d', PathHelper::DOT_NORMALIZE, '-'],
				],
				// function (\Ke\TestUtils\TestMethod $method) {
				//
				// },
			],
			function (PathHelper $helper, $index, \Ke\TestUtils\TestItem $item) {
			},
			function (PathHelper $helper, $index, \Ke\TestUtils\TestItem $item) {
				$this->assertSame($item->excepted, $item->invoke(), $item->message);
			}
		)->throwLastException();
	}
	
	public function test_bin_op()
	{
		$convertToBin = function ($int, $paddingLength = 6) {
			$rs = base_convert($int, 10, 2);
			return str_pad($rs, $paddingLength, '0', STR_PAD_LEFT);
		};
		
		$filterBinMode = function ($mode) {
			$mode      = $mode & PathHelper::PURGE_ALL_VALUE;
			$rightMode = ($mode >> 4) << 4;
			$leftMode  = (($mode ^ $rightMode) >> 2) << 2;
			$dotMode   = $mode ^ $rightMode ^ $leftMode;
			return [$dotMode, $leftMode, $rightMode];
		};
		
		$showDotModeText = function ($value) {
			switch ($value) {
				case PathHelper::DOT_ORIGINAL :
					return 'dot-original';
				case PathHelper::DOT_NORMALIZE :
					return 'dot-normalize';
			}
			return 'dot-remove';
		};
		
		$showStartModeText = function ($value) {
			switch ($value) {
				case PathHelper::LEFT_FILL:
					return 'start-fill';
				case PathHelper::LEFT_ORIGINAL:
					return 'start-original';
			}
			return 'start-remove';
		};
		
		$showEndModeText = function ($value) {
			switch ($value) {
				case PathHelper::RIGHT_FILL:
					return 'end-fill';
				case PathHelper::RIGHT_ORIGINAL:
					return 'end-original';
			}
			return 'end-remove';
		};
		
		$values = [
			[
				PathHelper::LR_ORIGINAL,
				[PathHelper::DOT_REMOVE, PathHelper::LEFT_ORIGINAL, PathHelper::RIGHT_ORIGINAL],
			],
			[
				PathHelper::LEFT_ORIGINAL,
				[PathHelper::DOT_REMOVE, PathHelper::LEFT_ORIGINAL, PathHelper::DOT_REMOVE],
			],
			[
				PathHelper::DOT_NORMALIZE | PathHelper::LEFT_ORIGINAL | PathHelper::RIGHT_FILL,
				[PathHelper::DOT_NORMALIZE, PathHelper::LEFT_ORIGINAL, PathHelper::RIGHT_FILL],
			],
		];
		
		foreach ($values as $value) {
			list($bin, $shouldBe) = $value;
			$parseResult = $filterBinMode($bin);
			list($dotMode, $startMode, $endMode) = $parseResult;
			echo 'bin        : ', $convertToBin($bin), PHP_EOL;
			echo 'dot-mode   : ', $convertToBin($dotMode), ', ', $showDotModeText($dotMode), PHP_EOL;
			echo 'start-mode : ', $convertToBin($startMode), ', ', $showStartModeText($startMode), PHP_EOL;
			echo 'end-mode   : ', $convertToBin($endMode), ', ', $showEndModeText($endMode), PHP_EOL;
			
			foreach ($shouldBe as $i => $v) {
				$this->assertSame($v, $parseResult[$i]);
			}
			
			echo '========================================', PHP_EOL;
		}
	}
	
	/**
	 * @testMethod convertDirectorySeparator
	 */
	public function test_convertDirectorySeparator()
	{
		$this->runMethodTest(
			$this->getLastAnnotationTestMethod(),
			[
				['D:/Projects/C#/MyLogger', ['D:\\Projects\\C#\\MyLogger', '/']],
				['D:\\Projects\\C#\\MyLogger', ['D:/Projects/C#/MyLogger', '\\']],
				['D:/Projects/C#/MyLogger/Test.cs', ['D:\\Projects/C#\\MyLogger/Test.cs']],
			],
			function (PathHelper $helper, $index, \Ke\TestUtils\TestItem $item) {
			},
			function (PathHelper $helper, $index, \Ke\TestUtils\TestItem $item) {
				$this->assertSame($item->excepted, $item->invoke());
			}
		)->throwLastException();
	}
	
	/**
	 *
	 * 该测试会在当前的 any 目录下添加目录，后再删除
	 *
	 * @testMethod prepareDirectory
	 */
	public function test_prepareDirectory()
	{
		$test = function ($inputPath, $isDir = false) {
			$dir = $this->helper->prepareDirectory($inputPath, $isDir);
			$this->assertTrue(is_dir($dir));
			if (is_dir($dir)) {
				rmdir($dir);
			}
		};
		
		$paths = [
			'./any/not_exists_dir_1/a.txt',
			['./any/not_exists_dir_2', true],
		];
		
		foreach ($paths as $path) {
			if (!is_array($path))
				$path = [$path];
			$test(...$path);
		}
	}
	
	/**
	 * @testMethod split
	 */
	public function test_split()
	{
		$this->runMethodTest(
			$this->getLastAnnotationTestMethod(),
			[
				[
					['/var/log', null, null, null],
					['/var/log/'],
				],
				[
					['/var/log', 'nginx.log', 'log', 'nginx'],
					['/var/log/nginx.log'],
				],
				[
					['/var/log', 'nginx.LOG', 'log', 'nginx'], // 文件名保持原样，但后缀名转为小写
					['/var/log/nginx.LOG'],
				],
				[
					['/var/log', 'nginx.20180930.log', 'log', 'nginx.20180930'], // 文件名中包含多个点，提取最右边的
					['/var/log/nginx.20180930.log'],
				],
				[
					['/usr/bin', 'http', null, 'http'], // 无后缀名，非 / 或 \ 结尾，表示为一个文件
					['/usr/bin/http'],
				],
				[
					['C:\\system32\\etc\\driver', 'hosts', null, 'hosts'], // windows style, 无后缀名，非 / 或 \ 结尾，表示为一个文件
					['C:\\system32\\etc\\driver\\hosts'],
				],
				[
					['C:\\system32\\etc\\driver', null, null, null], // win style， / 或 \ 结尾，表示为一个目录
					['C:\\system32\\etc\\driver\\'],
				],
			],
			function (PathHelper $helper, $index, \Ke\TestUtils\TestItem $item) {
			},
			function (PathHelper $helper, $index, \Ke\TestUtils\TestItem $item) {
				$results = $item->invoke();
				
				foreach ($results as $index => $result) {
					$this->assertSame($item->excepted[$index] ?? null, $result);
				}
			}
		)->throwLastException();
	}
}
